from threading import Condition, Thread


class SafeQueue:
    def __init__(self, size: int):
        self.__item_list = list()
        self.size = size
        self.__item_lock = Condition()

    def put(self, item):
        # self.__item_lock.acquire()
        #
        # # 醒来后 如果还是没地方 继续等待
        # while len(self.__item_list) >= self.size:
        #     self.__item_lock.wait()  # 等待 模拟阻塞
        #
        # self.__item_list.insert(0, item)
        # self.__item_lock.notify_all()  # 通知其他所有人醒来
        # self.__item_lock.release()

        # with 上下文管理器写法 自动加锁与释放
        with self.__item_lock:
            # while: 醒来后 如果还是没地方 继续等待
            while len(self.__item_list) >= self.size:
                self.__item_lock.wait()  # 等待 模拟阻塞

            self.__item_list.insert(0, item)
            self.__item_lock.notify_all()  # 通知其他所有人醒来

    def get(self):
        # self.__item_lock.acquire()
        # while len(self.__item_list) == 0:
        #     self.__item_lock.wait()
        #
        # result = self.__item_list.pop()
        # self.__item_lock.notify_all()  # 通知其他所有人醒来
        # self.__item_lock.release()
        # return result

        with self.__item_lock:
            while len(self.__item_list) == 0:
                self.__item_lock.wait()

            result = self.__item_list.pop()
            self.__item_lock.notify_all()  # 通知其他所有人醒来
            return result


class MyProducer(Thread):
    def __init__(self, name: str, count: int, queue: SafeQueue):
        super().__init__()

        self.setName(name)
        self.count = count
        self.queue = queue

    def run(self) -> None:
        for n in range(self.count):
            msg = f"{self.getName()} - {n}"
            self.queue.put(msg)  # 如果满了，等待


class MyConsumer(Thread):
    def __init__(self, name: str, queue: SafeQueue):
        super().__init__()

        self.setName(name)
        self.setDaemon(True)  # 守护线程，主线程结束，立刻结束
        self.queue = queue

    def run(self) -> None:
        # 一直运行
        while True:
            msg = self.queue.get()  # 没数据，等待
            print(f"{self.getName()} - {msg}\n", end="")


queue = SafeQueue(3)
threads = list()

threads.append(MyProducer("PA", 10, queue))
threads.append(MyProducer("PB", 10, queue))
threads.append(MyProducer("PC", 10, queue))

threads.append(MyConsumer("CA", queue))
threads.append(MyConsumer("CB", queue))


for t in threads:
    t.start()
